﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommonUtils;

namespace MudEngine.Parsing.AST
{
    public class ConstantExpression : Expression
    {
		private object _constValue;

        public ConstantExpression(string tokenValue, AType type)
        {
            if (tokenValue.Length > 0)
            {
				this.Type = type;
				switch (type.SystemType)
				{
					case ResultType.STRING: this._constValue = tokenValue.Substring(1, tokenValue.Length - 2).UnescapeString(); break;
					case ResultType.REAL: this._constValue = double.Parse(tokenValue); break;
					case ResultType.SHORT:
					case ResultType.INT:
					case ResultType.LONG: this.ParseValue(long.Parse(tokenValue)); break;
					case ResultType.BOOL: this._constValue = bool.Parse(tokenValue); break;
					default: throw new Exception("Unknown Literal type");
				}
            }
            else
                throw new Exception("Empty Constant expression");
        }

		private void ParseValue(long value)
		{
			if ((value > int.MaxValue) || (value < int.MinValue))
			{
				this._constValue = value;
				this.Type = AType.TYPE_LONG;
			}
			else if ((value > short.MaxValue) || (value < short.MinValue))
			{
				this._constValue = (int)value;
				this.Type = AType.TYPE_INT;
			}
			else
			{
				this._constValue = (short)value;
				this.Type = AType.TYPE_SHORT;
			}
		}

        public bool Bool
        {
            get
            {
                if (Type != AType.TYPE_BOOL)
                    throw new AccessViolationException("Value is not of type Bool");
				return (bool)this._constValue;
            }
        }

		public short Short
		{
			get
			{
				if (Type != AType.TYPE_SHORT)
					throw new AccessViolationException("Value is not of type Short");
				return (short)this._constValue;
			}
		}

		public int Int
		{
			get
			{
				if (Type != AType.TYPE_INT)
					throw new AccessViolationException("Value is not of type Int");
				return (int)this._constValue;
			}
		}

		public long Long
		{
			get
			{
				if (Type != AType.TYPE_LONG)
					throw new AccessViolationException("Value is not of type Long");
				return (long)this._constValue;
			}
		}

		public double Real
        {
            get
            {
				if (Type != AType.TYPE_REAL)
                    throw new AccessViolationException("Value is not of type Real");
				return (double)this._constValue;
            }
        }

        public string String
        {
            get
            {
				if (Type != AType.TYPE_STRING)
                    throw new AccessViolationException("Value is not of type String");
                return this._constValue.ToString();
            }
        }

		public override void AcceptVisitor<C>(IAstNodeVisitor<C> visitor, C ctx)
        {
            visitor.VisitConstantExpression(this, ctx);
        }
    }
}
